package http

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"multimedia/service"
	"multimedia/utils"
	"net/http"
	"net/url"
	"runtime"
	"strings"

	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
)

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		origin := c.Request.Header.Get("origin")
		c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, XMLHttpRequest, "+
			"Accept-Encoding, X-CSRF-Token, userId, Authorization")
		if c.Request.Method == "OPTIONS" {
			c.String(200, "ok")
			return
		}
		c.Next()
	}
}
func VertifyContentType() gin.HandlerFunc {
	contentTypeMap := map[string]bool{
		"application/x-www-form-urlencoded": true,
		"application/json":                  true,
		"multipart/form-data":               true,
		"":                                  true,
	}
	return func(c *gin.Context) {
		if _, ok := contentTypeMap[c.ContentType()]; !ok {
			type MAContentType struct {
				ErrStr string `json:"errstr"` // 错误码
			}
			pack := MAContentType{
				ErrStr: fmt.Sprintf("Content-Type is %s", c.ContentType()),
			}
			c.JSON(http.StatusBadRequest, pack)
			c.Abort()
			return
		}
		c.Next()
	}
}

func Start() error {
	if service.DataSrv == nil {
		log.WithField("func:", "service Start ").Errorf("service start error")
		return errors.New("the DataSrv is nil")
	}
	runtime.GOMAXPROCS(runtime.NumCPU())
	engine := gin.Default()
	engine.Use(Cors())
	engine.Use(VertifyContentType())
	engine.Use(Decode())
	gin.SetMode(gin.ReleaseMode)
	InitRouting(engine)
	go func() {
		err := engine.Run("0.0.0.0:8082")
		if err != nil {
			log.Errorf("Gin engine err:%v", err.Error())
		}
	}()
	log.WithField("func:", "service Start ").Infof("service start")

	return nil
}
func WSStart() error {
	runtime.GOMAXPROCS(runtime.NumCPU())
	gin.SetMode(gin.ReleaseMode)
	r := gin.Default()
	r.GET("/videochat/ws/:userId", func(c *gin.Context) {
		service.DataSrv.HandleRequest(c.Writer, c.Request, c)
	})
	go func() {
		r.Run("0.0.0.0:8032")
	}()

	return nil
}
func WhiteboardSrvStart() error {
	runtime.GOMAXPROCS(runtime.NumCPU())
	gin.SetMode(gin.ReleaseMode)
	r := gin.Default()
	r.GET("/whiteboard/record/:filename", func(c *gin.Context) {
		service.DataSrv.WhiteBoardRecord(c.Writer, c.Request, c)
	})
	go func() {
		r.Run("0.0.0.0:8033")
	}()
	return nil
}

func Decode() gin.HandlerFunc {
	return func(c *gin.Context) {
		if c.Request.Method == "GET" {
			replaceData, _ := url.QueryUnescape(c.Request.URL.RawQuery)
			str := strings.Replace(replaceData, " ", "", -1)
			str = strings.Replace(str, "data=", "", -1)
			res, err := utils.DecryptByAes(str)
			if err != nil {
				log.WithField("Func", "Decode").Warnf("get DecryptByAes error", err.Error())
				type MAContentType struct {
					ErrStr string `json:"errstr"` // 错误码
				}
				pack := MAContentType{
					ErrStr: fmt.Sprintf("get DecryptByAes url:%v error  %s", c.Request.URL, err.Error()),
				}
				c.JSON(http.StatusBadRequest, pack)
				c.Abort()
				return
			}
			c.Request.URL.RawQuery = string(res)
		} else if c.Request.Method == "POST" {
			urlList := []string{"/management/apps/", "/user/avatarUpload", "/user/avatarCircularUpload"}
			result := in(c.Request.URL.String(), urlList)
			if !result {
				var body []byte
				body, _ = io.ReadAll(c.Request.Body)
				var Confer utils.GetCiphertext
				_ = json.Unmarshal(body, &Confer)
				res, err := utils.DecryptByAes(Confer.Data)
				log.WithField("Func", "Decode").Infof("post the url is:%v,the before decryption is:%s, the After decryption is %s", c.Request.URL, Confer.Data, res)
				if err != nil {
					log.WithField("Func", "Decode").Warnf("post DecryptByAes error", err.Error())
					type MAContentType struct {
						ErrStr string `json:"errstr"` // 错误码
					}
					pack := MAContentType{
						ErrStr: fmt.Sprintf("post DecryptByAes url:%v error  %s", c.Request.URL, err.Error()),
					}
					c.JSON(http.StatusBadRequest, pack)
					c.Abort()
					return
				}
				//字节流放回到body中
				c.Request.Body = io.NopCloser(bytes.NewBuffer(res))
			}
		}
		c.Next()
	}
}
func in(target string, str_array []string) bool {
	for _, element := range str_array {
		if strings.Contains(target, element) {
			return true
		}
	}
	return false
}
